Opanuj obs艂ug臋 b艂臋d贸w w FastAPI dzi臋ki niestandardowym obs艂ugi wyj膮tk贸w. Naucz si臋 tworzy膰 solidne API z eleganckimi odpowiedziami na b艂臋dy, aby poprawi膰 UX i niezawodno艣膰 aplikacji.
Python FastAPI Obs艂uga b艂臋d贸w: Tworzenie solidnych niestandardowych obs艂ugi wyj膮tk贸w
\n\nObs艂uga b艂臋d贸w to kluczowy aspekt tworzenia solidnych i niezawodnych API. W FastAPI dla Pythona mo偶esz wykorzysta膰 niestandardowe obs艂ugi wyj膮tk贸w, aby elegancko zarz膮dza膰 b艂臋dami i dostarcza膰 klientom informacyjne odpowiedzi. Ten wpis na blogu przeprowadzi Ci臋 przez proces tworzenia niestandardowych obs艂ugi wyj膮tk贸w w FastAPI, umo偶liwiaj膮c budowanie bardziej odpornych i przyjaznych dla u偶ytkownika aplikacji.
\n\nDlaczego niestandardowe obs艂ugi wyj膮tk贸w?
\n\nFastAPI zapewnia wbudowane wsparcie dla obs艂ugi wyj膮tk贸w. Jednak poleganie wy艂膮cznie na domy艣lnych odpowiedziach na b艂臋dy mo偶e pozostawi膰 klient贸w z niejasnymi lub ma艂o pomocnymi informacjami. Niestandardowe obs艂ugi wyj膮tk贸w oferuj膮 kilka zalet:
\n\n- \n
- Poprawione do艣wiadczenie u偶ytkownika: Dostarczaj jasne i informacyjne komunikaty o b艂臋dach, dostosowane do konkretnych scenariuszy b艂臋d贸w. \n
- Scentralizowane zarz膮dzanie b艂臋dami: Skonsoliduj logik臋 obs艂ugi b艂臋d贸w w jednym miejscu, dzi臋ki czemu Tw贸j kod b臋dzie 艂atwiejszy w utrzymaniu. \n
- Sp贸jne odpowiedzi na b艂臋dy: Upewnij si臋, 偶e odpowiedzi na b艂臋dy maj膮 sp贸jny format, poprawiaj膮c u偶yteczno艣膰 API. \n
- Zwi臋kszone bezpiecze艅stwo: Zapobiegaj ujawnianiu wra偶liwych informacji w komunikatach o b艂臋dach. \n
- Niestandardowe logowanie: Loguj szczeg贸艂owe informacje o b艂臋dach w celach debugowania i monitorowania. \n
Zrozumienie obs艂ugi wyj膮tk贸w w FastAPI
\n\nFastAPI wykorzystuje po艂膮czenie wbudowanych w Pythona mechanizm贸w obs艂ugi wyj膮tk贸w i w艂asnego systemu wstrzykiwania zale偶no艣ci do zarz膮dzania b艂臋dami. Gdy wyj膮tek zostanie zg艂oszony w ramach 艣cie偶ki (route) lub zale偶no艣ci, FastAPI wyszukuje odpowiedni obs艂ug臋 wyj膮tk贸w, aby go przetworzy膰.
\n\nObs艂ugi wyj膮tk贸w to funkcje udekorowane @app.exception_handler(), kt贸re przyjmuj膮 dwa argumenty: typ wyj膮tku i obiekt 偶膮dania. Obs艂uga jest odpowiedzialna za zwr贸cenie odpowiedniej odpowiedzi HTTP.
Tworzenie niestandardowych wyj膮tk贸w
\n\nPrzed zdefiniowaniem niestandardowych obs艂ugi wyj膮tk贸w cz臋sto warto stworzy膰 niestandardowe klasy wyj膮tk贸w, kt贸re reprezentuj膮 specyficzne warunki b艂臋d贸w w Twojej aplikacji. Poprawia to czytelno艣膰 kodu i u艂atwia obs艂ug臋 r贸偶nych typ贸w b艂臋d贸w.
\n\nNa przyk艂ad, za艂贸偶my, 偶e budujesz API e-commerce i musisz obs艂u偶y膰 przypadki, gdy produkt jest niedost臋pny w magazynie. Mo偶esz zdefiniowa膰 niestandardow膮 klas臋 wyj膮tku o nazwie OutOfStockError:
\nclass OutOfStockError(Exception):\n def __init__(self, product_id: int):\n self.product_id = product_id\n self.message = f"Product with ID {product_id} is out of stock."\n
Ta niestandardowa klasa wyj膮tku dziedziczy po bazowej klasie Exception i zawiera atrybut product_id oraz niestandardowy komunikat o b艂臋dzie.
Implementacja niestandardowych obs艂ugi wyj膮tk贸w
\n\nTeraz utw贸rzmy niestandardowy obs艂ug臋 wyj膮tk贸w dla OutOfStockError. Ten obs艂ug臋 przechwyci wyj膮tek i zwr贸ci odpowied藕 HTTP 400 (Bad Request) z tre艣ci膮 JSON zawieraj膮c膮 komunikat o b艂臋dzie.
\nfrom fastapi import FastAPI, Request, HTTPException\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\nclass OutOfStockError(Exception):\n def __init__(self, product_id: int):\n self.product_id = product_id\n self.message = f"Product with ID {product_id} is out of stock."\n\n@app.exception_handler(OutOfStockError)\nasync def out_of_stock_exception_handler(request: Request, exc: OutOfStockError):\n return JSONResponse(\n status_code=400,\n content={\"message\": exc.message},\n )\n\n@app.get(\"/products/{product_id}\")\nasync def get_product(product_id: int):\n # Simulate checking product stock\n if product_id == 123:\n raise OutOfStockError(product_id=product_id)\n return {\"product_id\": product_id, \"name\": \"Example Product\", \"price\": 29.99}\n
W tym przyk艂adzie dekorator @app.exception_handler(OutOfStockError) rejestruje funkcj臋 out_of_stock_exception_handler do obs艂ugi wyj膮tk贸w OutOfStockError. Gdy wyj膮tek OutOfStockError zostanie zg艂oszony w 艣cie偶ce get_product, wywo艂ywana jest obs艂uga wyj膮tk贸w. Obs艂uga zwraca nast臋pnie JSONResponse ze statusem 400 i tre艣ci膮 JSON zawieraj膮c膮 komunikat o b艂臋dzie.
Obs艂uga wielu typ贸w wyj膮tk贸w
\n\nMo偶esz zdefiniowa膰 wiele obs艂ugi wyj膮tk贸w do obs艂ugi r贸偶nych typ贸w wyj膮tk贸w. Na przyk艂ad, mo偶esz chcie膰 obs艂u偶y膰 wyj膮tki ValueError, kt贸re wyst臋puj膮 podczas parsowania danych wej艣ciowych u偶ytkownika.
\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\n@app.exception_handler(ValueError)\nasync def value_error_exception_handler(request: Request, exc: ValueError):\n return JSONResponse(\n status_code=400,\n content={\"message\": str(exc)},\n )\n\n@app.get(\"/items/{item_id}\")\nasync def get_item(item_id: int):\n # Simulate invalid item_id\n if item_id < 0:\n raise ValueError("Item ID must be a positive integer.")\n return {\"item_id\": item_id, \"name\": \"Example Item\"}\n
W tym przyk艂adzie funkcja value_error_exception_handler obs艂uguje wyj膮tki ValueError. Wyodr臋bnia komunikat o b艂臋dzie z obiektu wyj膮tku i zwraca go w odpowiedzi JSON.
U偶ywanie HTTPException
\n\nFastAPI udost臋pnia wbudowan膮 klas臋 wyj膮tku o nazwie HTTPException, kt贸ra mo偶e by膰 u偶ywana do zg艂aszania b艂臋d贸w specyficznych dla HTTP. Mo偶e to by膰 przydatne do obs艂ugi typowych scenariuszy b艂臋d贸w, takich jak nieautoryzowany dost臋p lub brak zasobu.
\nfrom fastapi import FastAPI, HTTPException\n\napp = FastAPI()\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: int):\n # Simulate user not found\n if user_id == 999:\n raise HTTPException(status_code=404, detail="User not found")\n return {\"user_id\": user_id, \"name\": \"Example User\"}\n
W tym przyk艂adzie wyj膮tek HTTPException jest zg艂aszany ze statusem 404 (Not Found) i komunikatem szczeg贸艂owym. FastAPI automatycznie obs艂uguje wyj膮tki HTTPException i zwraca odpowied藕 JSON z okre艣lonym statusem i komunikatem szczeg贸艂owym.
Globalne obs艂ugi wyj膮tk贸w
\n\nMo偶esz r贸wnie偶 zdefiniowa膰 globalne obs艂ugi wyj膮tk贸w, kt贸re przechwytuj膮 wszystkie nieobs艂u偶one wyj膮tki. Mo偶e to by膰 przydatne do logowania b艂臋d贸w lub zwracania og贸lnego komunikatu o b艂臋dzie do klienta.
\n\n
\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\nimport logging\n\napp = FastAPI()\n\nlogger = logging.getLogger(__name__)\n\n@app.exception_handler(Exception)\nasync def global_exception_handler(request: Request, exc: Exception):\n logger.exception(f"Unhandled exception: {exc}")\n return JSONResponse(\n status_code=500,\n content={\"message\": \"Internal server error\"},\n )\n\n@app.get(\"/error\")\nasync def trigger_error():\n raise ValueError("This is a test error.")\n
W tym przyk艂adzie funkcja global_exception_handler obs艂uguje wszystkie wyj膮tki, kt贸re nie s膮 obs艂ugiwane przez inne obs艂ugi wyj膮tk贸w. Loguje b艂膮d i zwraca odpowied藕 500 (Internal Server Error) z og贸lnym komunikatem o b艂臋dzie.
U偶ywanie oprogramowania po艣rednicz膮cego (Middleware) do obs艂ugi wyj膮tk贸w
\n\nInnym podej艣ciem do obs艂ugi wyj膮tk贸w jest u偶ycie oprogramowania po艣rednicz膮cego (middleware). Funkcje middleware s膮 wykonywane przed i po ka偶dym 偶膮daniu, umo偶liwiaj膮c przechwytywanie i obs艂ug臋 wyj膮tk贸w na wy偶szym poziomie. Mo偶e to by膰 przydatne do zada艅 takich jak logowanie 偶膮da艅 i odpowiedzi, lub do implementacji niestandardowej logiki uwierzytelniania lub autoryzacji.
\n\n
\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\nimport logging\n\napp = FastAPI()\n\nlogger = logging.getLogger(__name__)\n\n@app.middleware("http")\nasync def exception_middleware(request: Request, call_next):\n try:\n response = await call_next(request)\n except Exception as exc:\n logger.exception(f"Unhandled exception: {exc}")\n return JSONResponse(\n status_code=500,\n content={\"message\": \"Internal server error\"},\n )\n return response\n\n@app.get(\"/error\")\nasync def trigger_error():\n raise ValueError("This is a test error.")\n
W tym przyk艂adzie funkcja exception_middleware otacza logik臋 przetwarzania 偶膮dania blokiem try...except. Je艣li wyj膮tek zostanie zg艂oszony podczas przetwarzania 偶膮dania, middleware loguje b艂膮d i zwraca odpowied藕 500 (Internal Server Error).
Przyk艂ad: Internacjonalizacja (i18n) i komunikaty o b艂臋dach
\n\nPodczas tworzenia API dla globalnej publiczno艣ci, rozwa偶 internacjonalizacj臋 komunikat贸w o b艂臋dach. Wi膮偶e si臋 to z dostarczaniem komunikat贸w o b艂臋dach w r贸偶nych j臋zykach, w zale偶no艣ci od ustawie艅 regionalnych u偶ytkownika. Chocia偶 pe艂na implementacja i18n wykracza poza zakres tego artyku艂u, oto uproszczony przyk艂ad demonstruj膮cy t臋 koncepcj臋:
\n\n
\nfrom fastapi import FastAPI, Request, HTTPException\nfrom fastapi.responses import JSONResponse\nfrom typing import Dict\n\napp = FastAPI()\n\n# Mock translation dictionary (replace with a real i18n library)\ntranslations: Dict[str, Dict[str, str]] = {\n \"en\": {\n \"product_not_found\": \"Product with ID {product_id} not found.\",\n \"invalid_input\": \"Invalid input: {error_message}\",\n },\n \"fr\": {\n \"product_not_found\": \"Produit avec l'ID {product_id} introuvable.\",\n \"invalid_input\": \"Entr茅e invalide\u00a0: {error_message}\",\n },\n \"es\": {\n \"product_not_found\": \"Producto con ID {product_id} no encontrado.\",\n \"invalid_input\": \"Entrada inv谩lida: {error_message}\",\n },\n \"de\": {\n \"product_not_found\": \"Produkt mit ID {product_id} nicht gefunden.\",\n \"invalid_input\": \"Ung眉ltige Eingabe: {error_message}\",\n }\n}\n\ndef get_translation(locale: str, key: str, **kwargs) -> str:\n \"\"\"Retrieves a translation for a given locale and key.\n If the locale or key is not found, returns a default message.\n \"\"\"\n if locale in translations and key in translations[locale]:\n return translations[locale][key].format(**kwargs)\n return f\"Translation missing for key '{key}' in locale '{locale}'.\"\n\n@app.get(\"/products/{product_id}\")\nasync def get_product(request: Request, product_id: int, locale: str = \"en\"):\n # Simulate product lookup\n if product_id > 100:\n message = get_translation(locale, \"product_not_found\", product_id=product_id)\n raise HTTPException(status_code=404, detail=message)\n\n if product_id < 0:\n message = get_translation(locale, \"invalid_input\", error_message=\"Product ID must be positive\")\n raise HTTPException(status_code=400, detail=message)\n\n return {\"product_id\": product_id, \"name\": \"Example Product\"}\n
Kluczowe ulepszenia dla przyk艂adu i18n:
\n\n- \n
- Parametr lokalizacji: 艢cie偶ka akceptuje teraz parametr zapytania
locale, umo偶liwiaj膮c klientom okre艣lenie preferowanego j臋zyka (domy艣lnie "en" dla angielskiego). \n - S艂ownik t艂umacze艅: S艂ownik
translations(mock) przechowuje komunikaty o b艂臋dach dla r贸偶nych lokalizacji (w tym przypadku angielski, francuski, hiszpa艅ski, niemiecki). W prawdziwej aplikacji u偶y艂by艣 dedykowanej biblioteki i18n. \n - Funkcja
get_translation: Ta pomocnicza funkcja pobiera odpowiednie t艂umaczenie na podstawielocaleikey. Obs艂uguje r贸wnie偶 formatowanie ci膮g贸w, aby wstawia膰 dynamiczne warto艣ci (takie jakproduct_id). \n - Dynamiczne komunikaty o b艂臋dach:
HTTPExceptionjest teraz zg艂aszany z komunikatemdetail, kt贸ry jest dynamicznie generowany przy u偶yciu funkcjiget_translation. \n
Gdy klient 偶膮da /products/101?locale=fr, otrzyma komunikat o b艂臋dzie w j臋zyku francuskim (je艣li t艂umaczenie jest dost臋pne). Gdy 偶膮da /products/-1?locale=es, otrzyma komunikat o b艂臋dzie dotycz膮cy ujemnego ID w j臋zyku hiszpa艅skim (je艣li dost臋pny). Gdy 偶膮da /products/200?locale=xx (lokalizacja bez t艂umacze艅), otrzyma komunikat `Translation missing`.
Najlepsze praktyki w obs艂udze b艂臋d贸w
\n\nOto kilka najlepszych praktyk, o kt贸rych nale偶y pami臋ta膰 podczas implementacji obs艂ugi b艂臋d贸w w FastAPI:
\n\n- \n
- U偶ywaj niestandardowych wyj膮tk贸w: Zdefiniuj niestandardowe klasy wyj膮tk贸w, aby reprezentowa膰 specyficzne warunki b艂臋d贸w w Twojej aplikacji. \n
- Dostarczaj informacyjne komunikaty o b艂臋dach: Do艂膮cz jasne i zwi臋z艂e komunikaty o b艂臋dach, kt贸re pomog膮 klientom zrozumie膰 przyczyn臋 b艂臋du. \n
- U偶ywaj odpowiednich kod贸w statusu HTTP: Zwracaj kody statusu HTTP, kt贸re dok艂adnie odzwierciedlaj膮 natur臋 b艂臋du. Na przyk艂ad, u偶yj 400 (Bad Request) dla nieprawid艂owych danych wej艣ciowych, 404 (Not Found) dla brakuj膮cych zasob贸w i 500 (Internal Server Error) dla nieoczekiwanych b艂臋d贸w. \n
- Unikaj ujawniania wra偶liwych informacji: Uwa偶aj, aby nie ujawnia膰 wra偶liwych informacji, takich jak dane uwierzytelniaj膮ce do bazy danych lub klucze API w komunikatach o b艂臋dach. \n
- Loguj b艂臋dy: Loguj szczeg贸艂owe informacje o b艂臋dach w celach debugowania i monitorowania. U偶yj biblioteki logowania, takiej jak wbudowany w Pythonie modu艂
logging. \n - Scentralizuj logik臋 obs艂ugi b艂臋d贸w: Skonsoliduj logik臋 obs艂ugi b艂臋d贸w w jednym miejscu, na przyk艂ad w niestandardowych obs艂uga wyj膮tk贸w lub middleware. \n
- Testuj obs艂ug臋 b艂臋d贸w: Napisz testy jednostkowe, aby upewni膰 si臋, 偶e Twoja logika obs艂ugi b艂臋d贸w dzia艂a poprawnie. \n
- Rozwa偶 u偶ycie dedykowanej us艂ugi 艣ledzenia b艂臋d贸w: W 艣rodowiskach produkcyjnych rozwa偶 u偶ycie dedykowanej us艂ugi 艣ledzenia b艂臋d贸w, takiej jak Sentry lub Rollbar, do monitorowania i analizowania b艂臋d贸w. Narz臋dzia te mog膮 dostarczy膰 cennych informacji na temat stanu Twojej aplikacji i pom贸c szybko zidentyfikowa膰 i rozwi膮za膰 problemy. \n
Wnioski
\n\nNiestandardowe obs艂ugi wyj膮tk贸w to pot臋偶ne narz臋dzie do budowania solidnych i przyjaznych dla u偶ytkownika API w FastAPI. Definiuj膮c niestandardowe klasy wyj膮tk贸w i obs艂ugi, mo偶esz elegancko zarz膮dza膰 b艂臋dami, dostarcza膰 klientom informacyjne odpowiedzi oraz poprawia膰 og贸ln膮 niezawodno艣膰 i 艂atwo艣膰 utrzymania swojej aplikacji. Po艂膮czenie niestandardowych wyj膮tk贸w, wyj膮tk贸w HTTP i wykorzystanie zasad i18n, gdy ma to zastosowanie, przygotowuje Twoje API na globalny sukces.
\n\nPami臋taj, aby wzi膮膰 pod uwag臋 do艣wiadczenie u偶ytkownika podczas projektowania strategii obs艂ugi b艂臋d贸w. Dostarczaj jasne i zwi臋z艂e komunikaty o b艂臋dach, kt贸re pomog膮 u偶ytkownikom zrozumie膰 problem i spos贸b jego rozwi膮zania. Skuteczna obs艂uga b艂臋d贸w to podstawa budowania wysokiej jako艣ci API, kt贸re spe艂niaj膮 potrzeby zr贸偶nicowanej, globalnej publiczno艣ci.